Skip to main content

Go Language Basics Quick Reference Guide

Glaringly Obvious Things (If You're New to Go)

  • No try/catch → Use error returns instead.
  • Functions are first-class citizens → Functions can be assigned to variables and passed around.
  • Runes → Go uses rune for Unicode characters (alias for int32).
  • No pointer arithmetic → Unlike C, you can't perform arithmetic on pointers.
  • Garbage collected → No manual memory management like malloc/free.
  • Everything starts with a main() function → Similar to C.
  • No while loop → Use for loops instead.
  • Interfaces are implemented implicitly → No implements keyword.
  • Link to Go Proverbs → Core philosophy and best practices.

Concepts And Syntax

Variables and Constants

var x int = 10
var y = 20 // Type inferred
z := 30 // Short declaration
const Pi = 3.14

Functions

func add(a int, b int) int {
return a + b
}

func main() {
result := add(2, 3)
fmt.Println(result)
}

Control Flow

If-Else

if x > 10 {
fmt.Println("x is greater than 10")
} else if x == 10 {
fmt.Println("x is 10")
} else {
fmt.Println("x is less than 10")
}

Switch

switch x {
case 1:
fmt.Println("One")
case 2, 3:
fmt.Println("Two or Three")
default:
fmt.Println("Other")
}

Loops

For Loop

for i := 0; i < 5; i++ {
fmt.Println(i)
}

While-Style Loop

x := 0
for x < 5 {
fmt.Println(x)
x++
}

Infinite Loop

for {
fmt.Println("Looping forever")
}

Arrays and Slices

var arr [3]int = [3]int{1, 2, 3} // Fixed-size array
slice := []int{4, 5, 6} // Dynamic slice
slice = append(slice, 7) // Append to slice

Maps (Hashmaps)

m := map[string]int{"foo": 42, "bar": 99}
m["baz"] = 100
fmt.Println(m["foo"]) // 42

Structs

type Person struct {
Name string
Age int
}

p := Person{Name: "Alice", Age: 25}
fmt.Println(p.Name)

Pointers

x := 10
ptr := &x // Pointer to x
fmt.Println(*ptr) // Dereference pointer

Goroutines (Concurrency)

func sayHello() {
fmt.Println("Hello")
}

go sayHello() // Run in a goroutine

Channels

ch := make(chan int)
go func() { ch <- 42 }()
x := <-ch // Receive from channel
fmt.Println(x)

Error Handling

func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}

Defer, Panic, and Recover

func main() {
defer fmt.Println("Executed at the end")
fmt.Println("Start")
}

Interfaces

type Speaker interface {
Speak() string
}

type Dog struct {}

func (d Dog) Speak() string {
return "Woof!"
}

var s Speaker = Dog{}
fmt.Println(s.Speak())

Generics (Go 1.18+)

type Number interface {
int | float64
}

func add[T Number](a, b T) T {
return a + b
}

Key Go Concepts to Understand

1. Value vs Reference Types

  • Only pointers, interfaces, slices, maps, channels, and function types can be nil.
  • Strings are value types, so they always have a default value ("", an empty string).
    • This is why sql.NullString exists, as it allows distinguishing between an empty string and nil.

2. String Concatenation Performance

  • Using += for string concatenation creates new allocations each time.
  • Using strings.Builder avoids extra allocations, making it more efficient for large string operations.

3. Go Profiler (pprof)

  • Use go tool pprof to analyze performance bottlenecks.
  • Example:
    go test -bench . -cpuprofile=cpu.out
    go tool pprof cpu.out

4. Garbage Collection and Escape Analysis

  • The Go runtime has garbage collection that runs automatically.
  • Use go build -gcflags="-m" to see escape analysis and check if variables are allocated on the heap or stack.

5. Zero Values Instead of Null

  • Go does not use null (like JavaScript or Java). Instead, types have zero values:
    • int0
    • string""
    • boolfalse
    • slice/mapnil

6. Struct Methods and Pointer Receivers

  • Methods on structs can have pointer receivers (*T) or value receivers (T).
  • Use a pointer receiver if the method modifies the struct.
    type Counter struct {
    Value int
    }

    func (c *Counter) Increment() {
    c.Value++
    }

7. Interface Satisfaction Is Implicit

  • There is no implements keyword in Go.
  • A type satisfies an interface if it has all required methods.

8. Avoiding Race Conditions

  • Use sync.Mutex or sync.RWMutex for safe concurrent access.
  • Example:
    var mu sync.Mutex
    count := 0

    func increment() {
    mu.Lock()
    defer mu.Unlock()
    count++
    }

9. Use context.Context for Cancellations

  • Many Go APIs accept context.Context for timeouts and cancellations.
  • Example:
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()